package com.atguigu.gmall.wms.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.consts.GmallConsts;
import com.atguigu.gmall.wms.vo.SkuLockVO;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.PageParamVo;

import com.atguigu.gmall.wms.mapper.WareSkuMapper;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atguigu.gmall.wms.service.WareSkuService;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {
    @Resource
    RedissonClient redissonClient;
    @Resource
    RabbitTemplate rabbitTemplate;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<WareSkuEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageResultVo(page);
    }

    @Override
    public List<SkuLockVO> checkAndLock(List<SkuLockVO> skuLockVOS) {
        //没有要锁库存的商品：
        if(CollectionUtils.isEmpty(skuLockVOS)){
            return null;
        }
        //1、遍历skuLockVOS 一个个验库存锁库存(需要保证原子性：可以细粒度给每个sku数据验证锁库存时加锁)
        skuLockVOS.forEach(skuLockVO -> {
            checkLock(skuLockVO);
        });
        //2、判断库存是否全部锁定成功
        //不是：释放锁定成功的库存
        //是： 返回锁定成功的数据(将锁定成功的库存信息缓存)
        List<SkuLockVO> lockFailVOS = skuLockVOS.stream().filter(skuLockVO -> !skuLockVO.getLock()).collect(Collectors.toList());
        List<SkuLockVO> lockSuccessVOS = skuLockVOS.stream().filter(skuLockVO -> skuLockVO.getLock()).collect(Collectors.toList());

        if(!CollectionUtils.isEmpty(lockFailVOS)){
            //有商品库存锁定失败
            if(!CollectionUtils.isEmpty(lockSuccessVOS)){
                //有锁定成功的商品信息：锁定成功的需要释放库存  一个订单中的多个商品有库存不足的
                lockSuccessVOS.forEach(lockFailVO->{
                   baseMapper.releaseStock(lockFailVO.getWareSkuId() , lockFailVO.getCount());
                });
            }
            return null;
        }
        //所有的商品锁定库存成功
        //将锁定成功的库存信息 保存到redis中：方便后面的业务释放库存
        stringRedisTemplate.opsForValue().set(GmallConsts.SKU_LOCK_SUCCESS_PREFIX+skuLockVOS.get(0).getOrderToken()
                , JSON.toJSONString(skuLockVOS));

        //锁定库存成功：设置定时释放库存
        //如果超过1个小时 订单还未创建/订单的状态仍然是支付成功以外的其他状态
        // 如果订单已存在  但是支付未成功：设置订单状态关闭
        // 释放库存
        //创建一个延迟队列： 队列中的消息过期时间为1小时 再给延迟队列绑定死信队列为wms.queue
        rabbitTemplate.convertAndSend("order.close.exchange",
                "order.close",
                    skuLockVOS.get(0).getOrderToken());
        return skuLockVOS;

    }

    @Override
    public void batchReleaseStock(String orderToken) {
        String lockSucJson = stringRedisTemplate.opsForValue().get(GmallConsts.SKU_LOCK_SUCCESS_PREFIX + orderToken);
        if(!StringUtils.isEmpty(lockSucJson)){
            //释放库存
            List<SkuLockVO> skuLockVOS = JSON.parseArray(lockSucJson, SkuLockVO.class);
            //释放所有的库存：远程访问wms服务
            skuLockVOS.forEach(skuLockVO -> {
                baseMapper.releaseStock(skuLockVO.getWareSkuId() , skuLockVO.getCount());
            });
            //删除redis中的缓存
            stringRedisTemplate.delete(GmallConsts.SKU_LOCK_SUCCESS_PREFIX + orderToken);
        }
    }

    @Override
    public void updateStockAndSales(SkuLockVO skuLockVO) {
        baseMapper.updateStockAndSales(skuLockVO.getWareSkuId() , skuLockVO.getCount());
    }

    //对一个商品验库存锁库存: 需要保证原子性
    private void checkLock(SkuLockVO skuLockVO) {
        //分布式锁：
        RLock fairLock = redissonClient.getFairLock(GmallConsts.SKU_LOCK_PREFIX+skuLockVO.getSkuId());
        try {
            //查询库存是否足够: select * from wms_ware_sku where sku_id = skuId and stock-stock_lock>= count;
            List<WareSkuEntity> wareSkuEntities = baseMapper.queryWareSkuStock(skuLockVO.getSkuId(),skuLockVO.getCount());

            //如果足够：锁定库存(修改stock_lock的值+skuLockVO的count)
            if(CollectionUtils.isEmpty(wareSkuEntities)){
                return;
            }
            // 挑选第一个仓库 修改stock_lock的值+count：
            //    update wms_ware_sku set stock_lock = stock_lock+count where id = xxx
            Long wareSkuId = wareSkuEntities.get(0).getId();
            int count = baseMapper.lockStock(skuLockVO.getCount() , wareSkuId);
            if(count==1){//锁定库存成功
                skuLockVO.setLock(true);
                skuLockVO.setWareSkuId(wareSkuId);//锁定库存成功的仓库
            }
        } finally {
            fairLock.unlock();
        }
    }

}